package com.gjy.service.uuid.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

/**
 * ID映射工具类
 * 用于将系统编码、机器编码、实例编码转换为雪花算法所需的数字ID
 *
 * @author gjy
 * @version 1.0
 * @since 2025-10-13 09:57:13
 */
public class IdMappingUtil {

    private static final Logger logger = LoggerFactory.getLogger(IdMappingUtil.class);

    // 系统编码映射表 (最多支持32个系统)
    private static final Map<String, Long> SYSTEM_CODE_MAP = new HashMap<>();

    // 机器编码映射表 (最多支持32台机器)
    private static final Map<String, Long> MACHINE_CODE_MAP = new HashMap<>();

    static {
        // 初始化系统编码映射
        SYSTEM_CODE_MAP.put("CHT_JS", 1L); // 江苏系统
        SYSTEM_CODE_MAP.put("CHT_JF", 2L); // 江苏分系统
        SYSTEM_CODE_MAP.put("CHT_SH", 3L); // 上海系统
        SYSTEM_CODE_MAP.put("CHT_BJ", 4L); // 北京系统
        SYSTEM_CODE_MAP.put("CHT_GZ", 5L); // 广州系统
        SYSTEM_CODE_MAP.put("CHT_SZ", 6L); // 深圳系统
        SYSTEM_CODE_MAP.put("CHT_HZ", 7L); // 杭州系统
        SYSTEM_CODE_MAP.put("CHT_NJ", 8L); // 南京系统
        SYSTEM_CODE_MAP.put("CHT_CD", 9L); // 成都系统
        SYSTEM_CODE_MAP.put("CHT_WH", 10L); // 武汉系统

        // 初始化机器编码映射
        MACHINE_CODE_MAP.put("192.168.253.111", 1L);
        MACHINE_CODE_MAP.put("10.33.12.3", 2L);
        MACHINE_CODE_MAP.put("192.168.1.100", 3L);
        MACHINE_CODE_MAP.put("192.168.1.101", 4L);
        MACHINE_CODE_MAP.put("10.0.0.100", 5L);
        MACHINE_CODE_MAP.put("10.0.0.101", 6L);
        MACHINE_CODE_MAP.put("172.16.0.100", 7L);
        MACHINE_CODE_MAP.put("172.16.0.101", 8L);
        MACHINE_CODE_MAP.put("192.168.0.100", 9L);
        MACHINE_CODE_MAP.put("192.168.0.101", 10L);

        logger.info("ID映射工具类初始化完成");
    }

    /**
     * 获取系统编码对应的数字ID
     *
     * @param systemCode 系统编码
     * @return 系统数字ID
     */
    public static long getSystemId(String systemCode) {
        if (systemCode == null || systemCode.trim().isEmpty()) {
            throw new IllegalArgumentException("系统编码不能为空");
        }

        Long systemId = SYSTEM_CODE_MAP.get(systemCode.toUpperCase());
        if (systemId == null) {
            // 如果映射表中不存在，使用哈希算法生成
            systemId = (long) (Math.abs(systemCode.hashCode()) % 32);
            logger.warn("系统编码 {} 未在映射表中找到，使用哈希值: {}", systemCode, systemId);
        }

        return systemId;
    }

    /**
     * 获取机器编码对应的数字ID
     *
     * @param machineCode 机器编码 (IP地址)
     * @return 机器数字ID
     */
    public static long getMachineId(String machineCode) {
        if (machineCode == null || machineCode.trim().isEmpty()) {
            throw new IllegalArgumentException("机器编码不能为空");
        }

        // 如果是IP地址，直接查找映射表
        Long machineId = MACHINE_CODE_MAP.get(machineCode);
        if (machineId != null) {
            return machineId;
        }

        // 如果是IP地址格式，使用IP地址的最后一段作为机器ID
        if (isValidIpAddress(machineCode)) {
            String[] parts = machineCode.split("\\.");
            if (parts.length == 4) {
                try {
                    long lastOctet = Long.parseLong(parts[3]);
                    machineId = lastOctet % 32;
                    logger.info("IP地址 {} 映射为机器ID: {}", machineCode, machineId);
                    return machineId;
                } catch (NumberFormatException e) {
                    logger.warn("解析IP地址失败: {}", machineCode);
                }
            }
        }

        // 如果都不是，使用哈希算法生成
        machineId = (long) (Math.abs(machineCode.hashCode()) % 32);
        logger.warn("机器编码 {} 未在映射表中找到，使用哈希值: {}", machineCode, machineId);

        return machineId;
    }

    /**
     * 获取实例编码对应的数字ID
     *
     * @param instanceCode 实例编码
     * @return 实例数字ID
     */
    public static long getInstanceId(String instanceCode) {
        if (instanceCode == null || instanceCode.trim().isEmpty()) {
            throw new IllegalArgumentException("实例编码不能为空");
        }

        try {
            long instanceId = Long.parseLong(instanceCode);
            if (instanceId < 0 || instanceId > 31) {
                throw new IllegalArgumentException("实例编码必须在0-31之间");
            }
            return instanceId;
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("实例编码必须是数字: " + instanceCode);
        }
    }

    /**
     * 验证IP地址格式
     *
     * @param ip IP地址字符串
     * @return 是否为有效IP地址
     */
    private static boolean isValidIpAddress(String ip) {
        if (ip == null || ip.trim().isEmpty()) {
            return false;
        }

        String[] parts = ip.split("\\.");
        if (parts.length != 4) {
            return false;
        }

        try {
            for (String part : parts) {
                int num = Integer.parseInt(part);
                if (num < 0 || num > 255) {
                    return false;
                }
            }
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 获取本机IP地址
     *
     * @return 本机IP地址
     */
    public static String getLocalIpAddress() {
        try {
            InetAddress localHost = InetAddress.getLocalHost();
            return localHost.getHostAddress();
        } catch (UnknownHostException e) {
            logger.warn("获取本机IP地址失败", e);
            return "127.0.0.1";
        }
    }

    /**
     * 添加系统编码映射
     *
     * @param systemCode 系统编码
     * @param systemId   系统ID
     */
    public static void addSystemMapping(String systemCode, long systemId) {
        if (systemId < 0 || systemId > 31) {
            throw new IllegalArgumentException("系统ID必须在0-31之间");
        }
        SYSTEM_CODE_MAP.put(systemCode.toUpperCase(), systemId);
        logger.info("添加系统编码映射: {} -> {}", systemCode, systemId);
    }

    /**
     * 添加机器编码映射
     *
     * @param machineCode 机器编码
     * @param machineId   机器ID
     */
    public static void addMachineMapping(String machineCode, long machineId) {
        if (machineId < 0 || machineId > 31) {
            throw new IllegalArgumentException("机器ID必须在0-31之间");
        }
        MACHINE_CODE_MAP.put(machineCode, machineId);
        logger.info("添加机器编码映射: {} -> {}", machineCode, machineId);
    }

    /**
     * 获取所有系统编码映射
     *
     * @return 系统编码映射表
     */
    public static Map<String, Long> getAllSystemMappings() {
        return new HashMap<>(SYSTEM_CODE_MAP);
    }

    /**
     * 获取所有机器编码映射
     *
     * @return 机器编码映射表
     */
    public static Map<String, Long> getAllMachineMappings() {
        return new HashMap<>(MACHINE_CODE_MAP);
    }

}
